//
//  t3d.m
//  Tekka's 3D Lib
//
//  Created by Tekka on 12-10-22.
//  Copyright (c) 2012年 Tekka. All rights reserved.
//

#import "t3d.h"

#pragma mark - Tekka's 3D Lib

#pragma mark - useful effect
void t3dLayerStepBackward(CALayer* layer, CGFloat radians)
{
    layer.transform = CATransform3DIdentity;
    [UIView animateWithDuration:0.4
                          delay:0
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         t3dLayerRotateAgainstBottomLine(layer, radians);
                     }
                     completion:^(BOOL finished){
                         if (!finished) return ;
                         layer.transform = t3dMatrixRotateAgainstBottomLine(radians, layer.bounds.size.height/2);
                         [UIView animateWithDuration:0.2
                                               delay:0
                                             options:UIViewAnimationOptionCurveEaseInOut
                                          animations:^(){
                                              layer.transform = CATransform3DMakeTranslation(0, 0, -layer.bounds.size.height*sin(radians));;
                                              }
                                              completion:nil
                          ];
                     }
     ];
}

void t3dLayerStepForward(CALayer* layer, CGFloat radians)
{
    layer.transform = CATransform3DMakeTranslation(0, 0,
                                                   -layer.bounds.size.height*sin(radians));;
    [UIView animateWithDuration:0.4
                          delay:0
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         t3dLayerRotateAgainstBottomLine(layer, radians);
                     }
                     completion:^(BOOL finished){
                         if (finished)
                         {
                             t3dLayerRotateAgainstBottomLine(layer, radians);
                             [UIView animateWithDuration:0.2
                                                   delay:0
                                                 options:UIViewAnimationOptionCurveEaseInOut
                                              animations:^(){
                                                  layer.transform = CATransform3DIdentity;
                                              }
                                              completion:nil
                              ];
                         }
                     }
     ];
}

#pragma mark - perspective projection
CATransform3D t3dMatrixPerspective(CGFloat distance, CGFloat radianAgainstYAxis, CGFloat radianAgainstXAxis)
{
	CATransform3D transform = CATransform3DMakeRotation(radianAgainstYAxis, 0, 1, 0);
	transform = CATransform3DRotate(transform, radianAgainstXAxis, 1, 0, 0);
	float zDistance = 500;
	transform.m34 = 1.0 / -zDistance;
	return transform;
}

void t3dLayerPerspective(CALayer* layer, CGFloat distance, CGFloat radianAgainstYAxis, CGFloat radianAgainstXAxis)
{
    layer.sublayerTransform = t3dMatrixPerspective(distance, radianAgainstYAxis, radianAgainstXAxis);
}

#pragma mark - rotate against bottom
CATransform3D t3dMatrixRotateAgainstBottomLine(CGFloat degree, CGFloat halfHeight)
{
    CATransform3D transform = CATransform3DMakeTranslation(0, halfHeight, 0);
    transform = CATransform3DRotate(transform, degree, 1, 0, 0);
    transform = CATransform3DTranslate(transform, 0, -halfHeight, 0);
    return transform;
}

void t3dLayerRotateAgainstBottomLine(CALayer* layer, CGFloat degree)
{
    layer.transform = t3dMatrixRotateAgainstBottomLine(degree, layer.bounds.size.height/2);
}

#pragma mark - rotate against top
CATransform3D t3dMatrixRotateAgainstTopLine(CGFloat degree, CGFloat halfHeight)
{
    CATransform3D transform = CATransform3DMakeTranslation(0, -halfHeight, 0);
    transform = CATransform3DRotate(transform, degree, 1, 0, 0);
    transform = CATransform3DTranslate(transform, 0, halfHeight, 0);
    return transform;
}

void t3dLayerRotateAgainstTopLine(CALayer* layer, CGFloat degree)
{
    layer.transform = t3dMatrixRotateAgainstTopLine(-degree, layer.bounds.size.height/2);
}

#pragma mark - rotate against left
CATransform3D t3dMatrixRotateAgainstLeftLine(CGFloat degree, CGFloat halfWidth)
{
    CATransform3D transform = CATransform3DMakeTranslation(-halfWidth, 0, 0);
    transform = CATransform3DRotate(transform, degree, 0, 1, 0);
    transform = CATransform3DTranslate(transform, halfWidth, 0, 0);
    return transform;
}

void t3dLayerRotateAgainstLeftLine(CALayer* layer, CGFloat degree)
{
    layer.transform = t3dMatrixRotateAgainstLeftLine(degree, layer.bounds.size.width/2);
}

#pragma mark - rotate against right
CATransform3D t3dMatrixRotateAgainstRightLine(CGFloat degree, CGFloat halfWidth)
{
    CATransform3D transform = CATransform3DMakeTranslation(halfWidth, 0, 0);
    transform = CATransform3DRotate(transform, -degree, 0, 1, 0);
    transform = CATransform3DTranslate(transform, -halfWidth, 0, 0);
    return transform;
}

void t3dLayerRotateAgainstRightLine(CALayer* layer, CGFloat degree)
{
    layer.transform = t3dMatrixRotateAgainstRightLine(degree, layer.bounds.size.width/2);
}

#pragma mark - tools function
CGFloat t3dDegreesToRadians(CGFloat degrees)
{
    return degrees * M_PI / 180;
}

CGFloat t3dRadiansToDegrees(CGFloat radians)
{
    return radians * 180 / M_PI;
}